﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cos.Core.Model.Membership;
using Cos.Core.NHibernate;
using Cos.Core.Security;
using Cos.Module.Membership.Data;
using Cos.Module.Membership.Exception;
using Microsoft.Practices.Unity;
using NHibernate;
using NHibernate.Criterion;

namespace Cos.Module.Membership.NHibernate
{
    public class MembershipRepository : RepositoryBase, IMembershipRepository
    {
        /**
     * {@inheritDoc}
     */
        //@Override
        [InjectionConstructor]
        public MembershipRepository(ISessionFactory sessionFactory)
            : base(sessionFactory)
        {
        }

        public MemberUser GetAuthenticationByUsername(string username, string applicationName) /*throws UserNotFoundException*/ {
            // Get the user
            var criteria = CurrentSession.CreateCriteria(typeof(UserDataModel));
            criteria.Add(Restrictions.Eq("UserName", username));
            var user = (UserDataModel)criteria.UniqueResult();

            if (user == null)
            {
                throw new UserNotFoundException("The username should not be null");
            }

            // Get the custom values
            IEnumerable<CustomUserFieldUserValueDataModel> customUserValues = GetCustomuserFields(username, applicationName);
            return MembershipModelToVoConverter.ConvertUserToAuthenticationVo(user, customUserValues);
        }

        /**
         * {@inheritDoc}
         */
        //@Override
        public MemberUser GetAuthenticationByEmail(String email, String applicationName)
        {
            // Get the user
            var criteria = CurrentSession.CreateCriteria(typeof(UserDataModel));
            criteria.Add(Restrictions.Eq("email", email));
            var user = (UserDataModel)criteria.UniqueResult();

            if (user == null)
            {
                throw new UserNotFoundException("The email should not be null");
            }

            // Get the custom values
            var customUserValues = GetCustomuserFields(user.Username, applicationName);

            return MembershipModelToVoConverter.ConvertUserToAuthenticationVo(user, customUserValues);
        }

        /**
         * {@inheritDoc}
         */
        //@Override
        public MemberUser GetAuthenticationByPkid(String userId, String applicationName)
        {
            // Check for invalid parameters
            if (userId == null)
            {
                throw new UserNotFoundException("The userId should not be null");
            }

            // Get the user
            var user = GetUserById(userId);

            if (user == null)
            {
                throw new UserNotFoundException("The user could not be found");
            }

            // Get the custom values
            var customUserValues = GetCustomuserFields(user.Username, applicationName);

            return MembershipModelToVoConverter.ConvertUserToAuthenticationVo(user, customUserValues);
        }

        /**
         * {@inheritDoc}
         */
        //@Override
        public void OnSuccessLogin(String userId)
        {
            // Get the user
            var user = GetUserById(userId);

            // update the user
            user.LastLoginDate = DateTime.Now;
            user.IsOnline = true;

            CurrentSession.SaveOrUpdate(user);
        }

        /**
         * {@inheritDoc}
         */
        //@Override
        public void OnFailedlLogin(String userId)
        {
            // Get the user
            var user = GetUserById(userId);

            // update the user
            user.FailedPasswordAttemptCount += 1;

            CurrentSession.SaveOrUpdate(user);
        }

        /**
         * {@inheritDoc}
         */
        //@Override
        public void OnSuccessLogout(String userId)
        {
            // Check for invalid parameters
            if (userId == null)
            {
                throw new UserNotFoundException("The userId should not be null");
            }

            // Get the user
            var user = GetUserById(userId);

            // update the user
            user.IsOnline = false;

            CurrentSession.SaveOrUpdate(user);
        }

        /**
         * {@inheritDoc}
         */
        //@Override
        public void ModifyUserEmail(String userId, String email)
        {
            if (userId == null)
            {
                throw new UserNotFoundException("The userId should not be null");
            }
            UserDataModel user = GetUserById(userId);

            if (user == null)
            {
                throw new UserNotFoundException("The user could not be found");
            }
            user.Email = email;
        }

        /**
         * {@inheritDoc}
         */
        //@Override
        public bool ValidateUserPassword(String userId, String password)
        {
            if (userId == null || password == null)
            {
                throw new UserNotFoundException("The userId and password should not be null");
            }

            var user = GetUserById(userId);

            if (user == null)
            {
                throw new UserNotFoundException("The user could not be found");
            }

            return HashHelper.GetMD5Hash(password).Equals(user.Password);
        }

        /**
         * {@inheritDoc}
         */
        //@Override
        public void ModifyUserPassword(String userId, String password)
        {
            if (userId == null || password == null)
            {
                throw new UserNotFoundException("The userId and password should not be null");
            }

            var user = GetUserById(userId);
            if (user == null)
            {
                throw new UserNotFoundException("The user could not be found");
            }
            user.Password = HashHelper.GetMD5Hash(password);
        }

        /**
         * {@inheritDoc}
         */
        private UserDataModel GetUserById(String userId)
        {
            return (UserDataModel)CurrentSession.Get(typeof(UserDataModel), userId);
        }

        /**
         * {@inheritDoc}
         */
        //@SuppressWarnings({ "unchecked" })
        private IEnumerable<CustomUserFieldUserValueDataModel> GetCustomuserFields(String username, String applicationName)
        {

            var query = CurrentSession.CreateSQLQuery(
                    "select {p.*} from CustomUserField_UserValue {p} where p.username = :username and " + "p.applicationName = :applicationName").AddEntity("p",
                    typeof(CustomUserFieldUserValueDataModel));

            query.SetString("username", username);
            query.SetString("applicationName", applicationName);

            return (IEnumerable<CustomUserFieldUserValueDataModel>)query.List();
        }

        private static void CreateUser(string applicationName, string userName, string password, string email, string pkid)
        {
            // TODO : need to implement CreateUser stored procedure functionnality
            throw new NotImplementedException();
        }

        /**
         * {@inheritDoc}
         */
        //@Override
        public String CreateUser(string applicationName, string userName, string password, string email, string[] groups)
        {
            var user = (UserDataModel)CurrentSession.CreateCriteria(typeof(UserDataModel))
                .Add(Restrictions.Eq("username", userName))
                .UniqueResult();

            if (user != null)
            {
                throw new DuplicateUserException(userName);
            }

            var pkid = Guid.NewGuid().ToString();

            CreateUser(applicationName, userName, password, email, pkid);
            
            foreach (var group in groups.Where(g => !string.IsNullOrEmpty(g)))
            {
                AddUserToRole(applicationName, userName, group);
            }

            return pkid;
        }

        private static void AddUserToRole(string applicationName, string userName, string group)
        {
            // TODO : need to implement stored procedure [dbo].[CreateUser] functionality
            throw new NotImplementedException();
        }

        //private static class CreateUser : Work {
        //    private String applicationName;

        //    private String userName;

        //    private String password;

        //    private String email;

        //    private String pkid;

        //    public CreateUser(String applicationName, String userName, String password, String email, String pkid) {
        //        this.applicationName = applicationName;
        //        this.userName = userName;
        //        this.password = password;
        //        this.email = email;
        //        this.pkid = pkid;
        //    }

        //    /**
        //     * {@inheritDoc}
        //     */
        //    //@Override
        //    public void execute(Connection connection)  {
        //        CallableStatement cState = connection.prepareCall("execute [dbo].[CreateUser] ?, ?, ?, ?, NULL, NULL, 1, ?");
        //        cState.setString(1, applicationName);
        //        cState.setString(2, userName);
        //        cState.setString(3, DigestUtils.md5Hex(password));
        //        cState.setString(4, email);
        //        cState.setString(5, pkid);

        //        cState.execute();
        //    }
        //}

        //private static class AddUserToRole : Work {
        //    private String applicationName;

        //    private String userName;

        //    private String group;

        //    public AddUserToRole(String applicationName, String userName, String group) {
        //        this.applicationName = applicationName;
        //        this.userName = userName;
        //        this.group = group;
        //    }

        //    /**
        //     * {@inheritDoc}
        //     */
        //    //@Override
        //    public void execute(Connection connection) throws SQLException {
        //        CallableStatement cState = connection.prepareCall("execute [dbo].[AddUserToRole] ?, ?, ?");
        //        cState.setString(1, applicationName);
        //        cState.setString(2, userName);
        //        cState.setString(3, group);

        //        cState.execute();
        //    }
        //}

        /**
         * {@inheritDoc}
         */
        //@Override
        public IEnumerable<string> GetRolesForNavId(int navId)
        {
            var query = CurrentSession.CreateSQLQuery("select * FROM PageGroupAccess WHERE navId = :navId").AddEntity(typeof(PageGroupAccessDataModel));
            query.SetInt32("navId", navId);

            // @SuppressWarnings("unchecked")
            var pgas = (IList<PageGroupAccessDataModel>)query.List();

            throw new NotImplementedException();
        }
    }
}
